//你好
const { def, base, intField, setEvent, regFieldGetSet, regEvent } = require("./jsdemo_windows.common.cpp.js");

const button_event = ["onClick"];
const button = String.raw/* cpp */`
  class Button : public Window{
    public:
    Button();
    ~Button();

    void render(int mask);
    void mouseDown(int x, int y, int e);
    void mouseUp(int x, int y, int e);
    void mouseMove(int x, int y, int e);
    void keyEvent(int key, int chr);

    char* title;
    int textX;
    int textY;
    int isDown;
    int downX;
    int downY;
    
${button_event.map((event)=>`
  JSValue ${event};
`).join("")}

  };

  Button::Button() : Window() {
    title = 0;
    width = 100;
    height = 26;
    textX = 5;
    textY = 5;
    isDown = 0;
    
${button_event.map((event)=> `
      ${event}.tag = JS_TAG_UNDEFINED;
`).join("")}
  }
  Button::~Button(){
    printf("~Button\n");
    if(title){
      free(title);
    }
    
    ${button_event.map((event)=>`
      JS_FreeValue(ctx, ${event});
`).join("")}

  }

  void Button::render(int mask){
    if((needRefresh)){
      if((beforeRender.tag & mask)!=JS_TAG_UNDEFINED){
        jsCall(beforeRender);
      }
      
      //no_frame = isDown ? 1 : 0;
      Window::render(0);
      int bg = getRGB565(bg_color);
      if(isDown){
        int shade = getRGB565(0xFFFFFF);
        int bright = getRGB565(0x808080);
        paint_pattern(abs_pos_x +         0 , abs_pos_y +          0 ,     2, height, (shade<<16) | bright, 0);
        paint_pattern(abs_pos_x +         0 , abs_pos_y +          0 , width,      2, (shade<<16) | bright, 0);
        paint_pattern(abs_pos_x + width - 2 , abs_pos_y +          0 ,     2, height,(bright<<16) |  shade, 0);
        paint_pattern(abs_pos_x +         0 , abs_pos_y + height - 2 , width,      2,(bright<<16) |  shade, 0);
      }else{
        int shade = getRGB565(0x808080);
        int bright = getRGB565(0xFFFFFF);
        paint_pattern(abs_pos_x            , abs_pos_y             ,     2, height, (shade<<16) | bright, 0);
        paint_pattern(abs_pos_x            , abs_pos_y             , width,      2, (shade<<16) | bright, 0);
        paint_pattern(abs_pos_x + width - 2, abs_pos_y             ,     2, height,(bright<<16) |  shade, 0);
        paint_pattern(abs_pos_x            , abs_pos_y + height - 2, width,      2,(bright<<16) |  shade, 0);

        //paint_pattern(abs_pos_x            , abs_pos_y             ,     2, height, (shade<<16) | bright, top ? 0 : 0x11112222);
        //paint_pattern(abs_pos_x            , abs_pos_y             , width,      2, (shade<<16) | bright, top ? 0 : 0xAAAA5555);
        //paint_pattern(abs_pos_x + width - 2, abs_pos_y             ,     2, height,(bright<<16) |  shade, top ? 0 : 0x11112222);
        //paint_pattern(abs_pos_x            , abs_pos_y + height - 2, width,      2,(bright<<16) |  shade, top ? 0 : 0xAAAA5555);
        //paint_pattern(abs_pos_x + 2        , abs_pos_y + 2         , width-4, height-4, bg, 0);
            
      }
      paint_pattern(abs_pos_x + 2        , abs_pos_y + 2         , width-4, height-4, bg, 0);
      //printf("id:%d\n", id);
      if(title){
        FILE* s = getStream(textX, textY, 200, 200);
        fprintf(s, title);
      }


      if((afterRender.tag & mask)!=JS_TAG_UNDEFINED){
        jsCall(afterRender);
      }
      if(mask){
        needRefresh = 0;
      }
    }

  }

  void Button::mouseDown(int x, int y, int e){
    isDown = 1;
    needRefresh = 1;
    downX = x;
    downY = y;
  }
  void Button::mouseUp(int x, int y, int e){
    isDown = 0;
    needRefresh = 1;
    if((downX-x)*(downX-x)<16 && (downY-y)*(downY-y)<16){
      if(onClick.tag!=JS_TAG_UNDEFINED){
        JSValue ret = JS_Call(ctx, onClick, js_obj, 0, 0);
        if (JS_IsException(ret)) {
            dump_exception(ctx, JS_GetException(ctx));
        }
        JS_FreeValue(ctx, ret);
      }
    }
  }
  void Button::mouseMove(int x, int y, int e){
  }
  void Button::keyEvent(int key, int chr){
    //TODO 空格/回车 触发 click
  }

  ${button_event.map((event)=>{
    return setEvent("Button", "button", event);
  }).join("")}
  
  static void js_button_calc_size(Button *p){
    p->height = 26;
    p->width = strlen(p->title)*8 + 10;
  }
  static JSValue js_button_ctor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv) {
    Button* p = new Button();
    JSValue obj = JS_NewObjectClass(ctx, js_button_class_id);
    p->js_obj = obj;
    JS_SetOpaque(obj, p);
    return obj;
  }
  static void js_button_finalizer(JSRuntime *rt, JSValue val) {
    Button *p = (Button*)JS_GetOpaque(val);
    if(p){
      delete p;
    }
  }

  static JSValue js_button_set_title(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
      Button *p = (Button*)JS_GetOpaque(this_val);
      if(p){
        if(p->title){
          free(p->title);
        }
        size_t len; char* str = (char*)JS_ToCStringLen(ctx, &len, argv[0]);
        p->title = (char*)malloc(len+1);
        memcpy(p->title, str, len+1);
        JS_FreeCString(ctx, str);
        js_button_calc_size(p);
        p->needRefresh = 1;
      }
      return JS_UNDEFINED;
  }

  void button_init(JSValue* window_ctor, JSValue* window_proto) {
    JS_NewClassID(&js_button_class_id);
    JSClassDef button_def = {
      .class_name = "Button",
      .finalizer = js_button_finalizer,
    };
    JS_NewClass(rt, js_button_class_id, &button_def);

    JSValue button_proto = JS_NewObject(ctx);

    // 添加 getter
    JS_DefinePropertyGetSet(ctx, button_proto, JS_NewAtom(ctx, "title"), JS_UNDEFINED, JS_NewCFunction(ctx, js_button_set_title, "title", 1), JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE);

    JS_SetClassProto(ctx, js_button_class_id, button_proto);

${button_event.map((event)=>{
  return regEvent("button", "button_proto", event);
}).join("")}

    JSValue button_ctor = JS_NewCFunction2(ctx, js_button_ctor, "Button", 2, JS_CFUNC_constructor, 0);
    JS_SetConstructor(ctx, button_ctor, button_proto);
    JS_SetPropertyStr(ctx, global, "Button", button_ctor);

    JS_SetPrototype(ctx, button_proto, *window_proto);
    JS_SetPrototype(ctx, button_ctor, *window_ctor);
  }  
`;

module.exports = { button };









    //JS_SetPropertyStr(ctx, button_proto, "render", JS_NewCFunction(ctx, js_button_render, "render", 0));

  // static JSValue js_button_render(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
  //     Button *p = (Button*)JS_GetOpaque(this_val);
  //     printf("js_button_render start\n");
  //     if(p){
  //       p->render();
  //     }
  //     printf("js_button_render end\n");
  //     return JS_UNDEFINED;
  // }

  //  JS_DefinePropertyGetSet(ctx, button_proto, JS_NewAtom(ctx, "title"), JS_NewCFunction(ctx, js_button_get_title, "title", 0), JS_NewCFunction(ctx, js_button_set_title, "title", 1), JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE);
  // static JSValue js_button_get_title(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
  //     Button *p = (Button*)JS_GetOpaque(this_val);
  //     if(p){
  //       return JS_NewString(ctx, p->title);
  //     }
  // }


// if(argc>=1 && JS_IsObject(argv[0])) {
//   JSValue val = argv[0];
//   getIntVal(val, "left", &(p->left));
//   getIntVal(val, "top", &(p->top));

//   JSValue title_obj = JS_GetPropertyStr(ctx, val, "title");
//   if(JS_IsString(title_obj)) {
//     char *str = (char*)JS_ToCString(ctx, title_obj);
//     if (str) {
//       p->title = str;
//       js_button_calc_size(p);
//     }
//   }
// }
